package com.ljs.module.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.ljs.module.annotation.IgnoreField;
import com.ljs.module.entity.ConfigProperties;
import com.ljs.module.entity.template.systemconfig.ConfigItem;
import org.apache.commons.lang3.StringUtils;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 注入Configuration文件
 * Created by lijunsai on 2021/07/12
 */
public class ConfigurationPatchUtil {

    public static String insertConfiguration(ConfigItem configItem, String path) {
        return insertConfiguration(configItem.getTabName(), configItem.getGroupName()
                , configItem.getItemNumber(), configItem.getClassName(), path, configItem.getConfigProperties());
    }

    /**
     * 将信息插入到ConfigurationPatch.js中
     * @param tabName 标签名
     * @param groupName 组名
     * @param number 排序
     * @param className 类名
     * @param filePath ConfigurationPatch.js文件路径
     * @return 操作结果
     */
    public static String insertConfiguration(String tabName, String groupName, String number, String className, String filePath, ConfigProperties configProperties){
        try {
            ScriptEngineManager sem=new ScriptEngineManager();
            ScriptEngine engine=sem.getEngineByName("javascript");
            BufferedReader read = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "UTF-8"));
            engine.eval(read);
            //定义js函数
            engine.eval("function addConfig(tabName,groupName,number,className){\n" +
                    "    if (!ConfigurationPatch.extensionPoints) {\n" +
                    "        ConfigurationPatch.extensionPoints = {};\n" +
                    "    }\n" +
                    "    if (!ConfigurationPatch.extensionPoints.SystemConfig) {\n" +
                    "        ConfigurationPatch.extensionPoints.SystemConfig = {};\n" +
                    "    }\n" +
                    "    if (!ConfigurationPatch.extensionPoints.SystemConfig.configItem) {\n" +
                    "        ConfigurationPatch.extensionPoints.SystemConfig.configItem = [];\n" +
                    "    }\n" +
                    "    return JSON.stringify(ConfigurationPatch);\n" +
                    "}");
            Invocable jsInvoke =(Invocable)engine; //Invocable是ScriptEngine的一个接口，调用函数需要强转
            String ret = (String)jsInvoke.invokeFunction("addConfig", new Object[]{tabName, groupName, number, className});
            read.close();
            // 格式化JSON
            JSONObject object = JSONObject.parseObject(ret);
            JSONObject systemConfig = object.getJSONObject("extensionPoints").getJSONObject("SystemConfig");
            JSONArray jsonArray = systemConfig.getJSONArray("configItem");
            List<ConfigItem> configItems = jsonArray.toJavaList(ConfigItem.class);
            boolean isOverride = false;
            // 原本列表为空直接添加
            if (configItems.size() == 0) {
                configItems.add(new ConfigItem(tabName, groupName, className, number));
            } else {
                // 查看是否重复
                List<ConfigItem> check = configItems.stream().filter(x -> x.getClassName().equals(className)).collect(Collectors.toList());
                // 判断是否覆盖
                if (!configProperties.isOverride() && check.size() > 0) {
                    return "更新Configuration失败," + className + "在文件中已存在<br>";
                } else {
                    if (check.size() > 0) {
                        // 清除掉重复的ConfigItem
                        configItems = configItems.stream()
                                .filter(x -> !check.stream().map(y -> y.getClassName()).collect(Collectors.toList()).contains(x.getClassName()))
                                .collect(Collectors.toList());
                        isOverride = true;
                    }
                    Integer max = configItems.stream()
                            .map(x -> StringUtils.isBlank(x.getItemNumber()) ? 0 : Integer.parseInt(x.getItemNumber()))
                            .max(Comparator.comparingInt(x -> x)).get();
                    configItems.add(new ConfigItem(tabName, groupName, className, max + 1 + ""));
                }
            }
            systemConfig.put("configItem", configItems);
            PropertyPreFilters filters = new PropertyPreFilters();
            PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
            List<Field> declaredFields = Util.getAllField(ConfigItem.class);
            for (Field declaredField : declaredFields) {
                IgnoreField annotation = declaredField.getAnnotation(IgnoreField.class);
                if (annotation != null) {
                    excludefilter.addExcludes(declaredField.getName());
                }
            }
            String pretty = JSON.toJSONString(object,excludefilter, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                    SerializerFeature.WriteDateUseDateFormat);
            pretty = "var ConfigurationPatch = " + pretty;
            FileOutputStream fos = new FileOutputStream(new File(filePath));
            fos.write(pretty.getBytes("UTF-8"));
            fos.close();
            return "更新Configuration成功;" + (isOverride ? className + "已存在，执行了覆盖操作" : "") + "<br>";
        } catch (Exception e) {
            return "更新Configuration失败<br>";
        }
    }
}
